#include "HAL.h"

/* PROTECTED REGION ID(Controller::HAL_customCode) ENABLED START */

#include <stdint.h>
#include <string.h>

#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"

#include "hw_memmap.h"
#include "hw_types.h"
#include "hw_adc.h"
#include "sysctl.h"
#include "adc.h"
#include "interrupt.h"
#include "timer.h"
#include "gpio.h"
#include "pwm.h"
#include "uartstdio.h"

#include "drivers/rit128x96x4.h"

#include "fixedpoint.h"
#include "Button.h"

#define ADC_COUNTER 10

static xSemaphoreHandle HAL_uart_mutex;

#if 0
static int convertADCtoTemperature(int32_t adcValue) {
	return FIX_MUL(FIX_DIV(FIX_FROM_INT(100/*K*/), FIX_FROM_INT(970/*Ohm*/)), FIX_DIV(FIX_FROM_INT(2200/*Ohm*/), FIX_MUL(FIX_DIV(FIX_FROM_INT(33/*0.1V*/),
									FIX_FROM_INT(30/*0.1V*/)), FIX_DIV(FIX_FROM_INT(1023), adcValue)) - FIX_FROM_INT(1)) - FIX_FROM_INT(1000/*Ohm*/)) + FIX_FROM_INT(25/*K*/);
}
#endif

static int32_t convertADCtoTemperature(int32_t adcValue) {
	int32_t vkty = FIX_DIV(FIX_MUL(FIX_FROM_INT(3), adcValue) + FIX_DIV(77059, 10), FIX_DIV(86004, 1000));
	int32_t rkty = FIX_MUL(FIX_DIV(FIX_MUL(vkty, FIX_FROM_INT(22)), FIX_FROM_INT(330) - vkty), FIX_FROM_INT(100));
	int32_t t = FIX_DIV(FIX_MUL(25, rkty), 209) - FIX_DIV(94617, 1000);
	return t;
}

void adcSequence0Handler(void) {
	static int32_t average = 0;
	static int adcCounter = ADC_COUNTER;

	unsigned long value;

	ADCIntClear(ADC0_BASE, 0);
	ADCSequenceDataGet(ADC0_BASE, 0, &value);

	average += value;

	if (--adcCounter == 0) {
		average = convertADCtoTemperature(FIX_DIV(FIX_FROM_INT(average), FIX_FROM_INT(ADC_COUNTER)));
		HAL_actualTemperature_send(&average);
		average = 0;
		adcCounter = ADC_COUNTER;
	}
}

void portEHandler(void) {
	GPIOPinIntClear(GPIO_PORTE_BASE, GPIO_PIN_0 | GPIO_PIN_1);

	if (TimerIntStatus(TIMER1_BASE, false) & TIMER_TIMA_TIMEOUT) {
		KeypadEvent keypadEvent = { 0 };

		TimerIntClear(TIMER1_BASE, TIMER_TIMA_TIMEOUT);
		TimerConfigure(TIMER1_BASE, TIMER_CFG_32_BIT_OS);
		TimerLoadSet(TIMER1_BASE, TIMER_A, SysCtlClockGet() / 5);
		TimerEnable(TIMER1_BASE, TIMER_A);

		if (!GPIOPinRead(GPIO_PORTE_BASE, GPIO_PIN_0)) {
			keypadEvent.keyCode |= BUTTON_UP;
		}

		if (!GPIOPinRead(GPIO_PORTE_BASE, GPIO_PIN_1)) {
			keypadEvent.keyCode |= BUTTON_DOWN;
		}

		HAL_keypad_send(&keypadEvent);
	}
}

/* PROTECTED REGION END */

void HAL_Runnable_initialize(void) {
	/* PROTECTED REGION ID(Controller::HAL_RunnableInitializeFunc) ENABLED START */
	HAL_uart_mutex = xSemaphoreCreateMutex();
	/* PROTECTED REGION END */
}

void HAL_Runnable(void) {
	/* PROTECTED REGION ID(Controller::HAL_RunnableFunc) ENABLED START */
	int32_t power;
	HAL_power_receive(&power);
	PWMPulseWidthSet(PWM_BASE, PWM_OUT_2, (PWMGenPeriodGet(PWM_BASE, PWM_GEN_1) - 4) * power / 100);
	/* PROTECTED REGION END */
}

void HAL_uart_writeString(const char *s) {
	/* PROTECTED REGION ID(Controller::ConsoleInterface::writeString) ENABLED START */
	if (xSemaphoreTake(HAL_uart_mutex, portMAX_DELAY) == pdTRUE) {
		UARTprintf("%s", s);
		xSemaphoreGive(HAL_uart_mutex);
	}
	/* PROTECTED REGION END */
}

int HAL_display_getWidth() {
	/* PROTECTED REGION ID(Controller::DisplayInterface::getWidth) ENABLED START */
	return 128;
	/* PROTECTED REGION END */
}

int HAL_display_getHeight() {
	/* PROTECTED REGION ID(Controller::DisplayInterface::getHeight) ENABLED START */
	return 96;
	/* PROTECTED REGION END */
}

void HAL_display_getStringSize(const char *s, int *width, int *height) {
	/* PROTECTED REGION ID(Controller::DisplayInterface::getStringSize) ENABLED START */
	*width = strlen(s) * 8;
	*height = 8;
	/* PROTECTED REGION END */
}

void HAL_display_drawString(const char *s, int x, int y) {
	/* PROTECTED REGION ID(Controller::DisplayInterface::drawString) ENABLED START */
	taskENTER_CRITICAL();
	{
		RIT128x96x4StringDraw(s, x << 1, y, 15);
	}
	taskEXIT_CRITICAL();
	/* PROTECTED REGION END */
}
